package com.zhentao.login.config;

import com.alibaba.fastjson2.JSONObject;
import com.zhentao.login.constants.Constants;
import com.zhentao.login.filter.JwtFilter;
import com.zhentao.login.utils.JwtToken;
import com.zhentao.login.utils.Result;
import com.zhentao.nlz.project.login.TUser;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Resource
    JwtFilter jwtAuthorizationFilter;
    @Resource
    JwtToken jwtToken;
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        //关闭csrf攻击
        http.csrf(AbstractHttpConfigurer::disable);
        //拦截权限 引入动态权限
        http.authorizeHttpRequests(conf->conf
                .requestMatchers("/service-user/user/login","/logout","/service-user/user/getUserinfo","/img/upload/**","/service-user/**")
                .permitAll().anyRequest().access(new AuthenticatedAuthorizationManager<>())
        );
        //登录表单
        http.formLogin(conf->conf
                .loginProcessingUrl("/user/login")
                .successHandler(this::onAuthenticationSuccess)
                .failureHandler(this::onAuthenticationFailure)
        );
        //异常信息处理
        http.exceptionHandling(conf->conf
                .authenticationEntryPoint(this::commence)
                .accessDeniedHandler(this::handle)
        );
        //关闭session
        http.sessionManagement(conf->conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        //引入认证证过滤
        http.addFilterBefore(jwtAuthorizationFilter, LogoutFilter.class);
        http.cors(conf->conf.configurationSource(corsConfiguration()));
        //退出登录
        http.logout(conf->conf
                .logoutUrl("/logout")
                .logoutSuccessHandler(this::onLogoutSuccess)
        );
        return http.build();
    }
    /*
     * 登录认证成功处理
     * */
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        TUser user =(TUser) authentication.getPrincipal();
        //根据user的id生成token 并将token当成key,将tuser对象当成value 存入redis 返回token
        String token = jwtToken.createJetToken(user);
        //获取前端传过来的rememberMe
        String rememberMe = request.getParameter("rememberMe");
        //redis存放用户数据
        if (Boolean.parseBoolean(rememberMe)) {
            //勾选了记住我
            //token存的是userId，我们要将userid生成token当key 放入redis 7天
            jwtToken.refreshToken(user, Constants.EXPIRE_TIME, TimeUnit.SECONDS);
        }else{
            //token存的是userId，我们要将userid生成token当key 放入redis 30分钟
            jwtToken.refreshToken(user, Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS);
        }
        response.getWriter().write(JSONObject.toJSONString(Result.success().put("token",token)));
    }
    /*
     * 登录认证失败处理
     * */
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSONObject.toJSONString(Result.error(401,"登录认证失败")));
    }
    /*
     * 身份验证失败
     * */
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSONObject.toJSONString(Result.error(401,"身份验证失败")));

    }
    /*
     * 权限不足
     * */
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSONObject.toJSONString(Result.error(403,"权限不足")));
    }
    /*
     * 退出成功
     * */
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        TUser loginUser=(TUser) authentication.getPrincipal();
        //根据用户对象的id去删除token
        if(loginUser!=null){
            jwtToken.removeToken(loginUser);
        }
        response.getWriter().write(JSONObject.toJSONString(Result.success("退出成功")));
    }


    //配置跨域
    public CorsConfigurationSource corsConfiguration() {
        CorsConfiguration corsConfiguration=new CorsConfiguration();
        //跨域的配置
        //corsConfiguration.setAllowedMethods(Arrays.asList("GET","POST","DELETE","BATCH"));
        //两种方法都是判断哪些请求允许跨域
        corsConfiguration.setAllowedMethods(Collections.singletonList("*"));
        corsConfiguration.setAllowedHeaders(Collections.singletonList("*"));
        corsConfiguration.setAllowedOrigins(Collections.singletonList("*")); //ip
        //创建
        UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration);
        return source;
    }
}
